#ifndef _RULES_H_
#define _RULES_H_

#include <list>
#include <netinet/in.h>

#include "Operation.h"

class RuleCompiler;

/*
 * AbstractRule
 */

class AbstractRule {
	friend class RuleCompiler;
protected:
	bool isTcp;
	virtual void compile(RuleCompiler &compiler, const Operation &oper) = 0;
	virtual AbstractRule *clone(void) const = 0;
	inline unsigned long getWord(unsigned long *dataIp,
			unsigned long *dataTcp, unsigned long offset) const
	{
		unsigned long *data = (isTcp) ? dataTcp : dataIp;
		if (sizeof(unsigned long) == 4)
			return ntohl(data[offset]);
		unsigned long tmp1 = ntohl(data[offset] & 0xffffffffUL);
		unsigned long tmp2 = ntohl(data[offset] >> 32);
		return (tmp2 << 32) | tmp1;
	}
public:
	virtual bool check(unsigned long *prevIp, unsigned long *curIp,
		unsigned long *prevTcp, unsigned long *curTcp) const = 0;
};

/*
 * ProxyRule
 */

class ProxyRule : public AbstractRule {
	friend class RuleCompiler;
protected:
	AbstractRule *rule;
	virtual void compile(RuleCompiler &compiler, const Operation &oper);
	virtual AbstractRule *clone(void) const = 0;
	void set(AbstractRule *src);
	AbstractRule *get(void);
public:
	virtual bool check(unsigned long *prevIp, unsigned long *curIp,
		unsigned long *prevTcp, unsigned long *curTcp) const = 0;
	virtual ~ProxyRule();
	ProxyRule() : rule(0) {}
};

/*
 * RootRule
 */

class RootRule : public ProxyRule {
	friend class RuleCompiler;
protected:
	using ProxyRule::rule;
	virtual AbstractRule *clone(void) const;
public:
	virtual bool check(unsigned long *prevIp, unsigned long *curIp,
			unsigned long *prevTcp, unsigned long *curTcp) const;
};

/*
 * ComplexRule
 */

class ComplexRule : public AbstractRule {
	friend class RuleCompiler;
protected:
	std::list<AbstractRule *> rules;
	void push_back(AbstractRule *rule);
	AbstractRule *back(void);
	virtual void compile(RuleCompiler &compiler, const Operation &oper);
	virtual AbstractRule *clone(void) const = 0;
public:
	virtual bool check(unsigned long *prevIp, unsigned long *curIp,
		unsigned long *prevTcp, unsigned long *curTcp) const = 0;
	virtual ~ComplexRule();
};

/*
 * ComplexANDRule
 */

class ComplexANDRule : public ComplexRule {
	friend class RuleCompiler;
protected:
	using ComplexRule::rules;
	virtual AbstractRule *clone(void) const;
public:
	virtual bool check(unsigned long *prevIp, unsigned long *curIp,
			unsigned long *prevTcp, unsigned long *curTcp) const;
};

/*
 * ComplexORRule
 */

class ComplexORRule : public ComplexRule {
	friend class RuleCompiler;
protected:
	using ComplexRule::rules;
	virtual AbstractRule *clone(void) const;
public:
	virtual bool check(unsigned long *prevIp, unsigned long *curIp,
			unsigned long *prevTcp, unsigned long *curTcp) const;
};

/*
 * NOTRule
 */

class NOTRule : public ProxyRule {
	friend class RuleCompiler;
protected:
	using ProxyRule::rule;
	virtual AbstractRule *clone(void) const;
public:
	virtual bool check(unsigned long *prevIp, unsigned long *curIp,
			unsigned long *prevTcp, unsigned long *curTcp) const;
};

/*
 * EqualsRule
 */

class EqualsRule : public AbstractRule {
	friend class RuleCompiler;
protected:
	unsigned long mask;
	unsigned long value;

	unsigned long offset;

	virtual void compile(RuleCompiler &compiler, const Operation &oper);
	virtual AbstractRule *clone(void) const;
public:
	virtual bool check(unsigned long *prevIp, unsigned long *curIp,
			unsigned long *prevTcp, unsigned long *curTcp) const;
};

/*
 * DifferRule
 */

class DifferRule : public AbstractRule {
	friend class RuleCompiler;
protected:
	unsigned long mask;
	unsigned long delta;

	unsigned long offset;

	virtual void compile(RuleCompiler &compiler, const Operation &oper);
	virtual AbstractRule *clone(void) const;
public:
	virtual bool check(unsigned long *prevIp, unsigned long *curIp,
			unsigned long *prevTcp, unsigned long *curTcp) const;
};

#endif
